#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include <Judy.h>

#include "model.h"
#include "datatypes.h"
#include "limits.h"

// two ids of type int + the underscore in between
unsigned char exists_restriction_buffer[16];
#define BUILD_EXISTS_RESTRICTION_ID(r,f) snprintf((char*) exists_restriction_buffer,16,"%d_%d",r,f)

// static char* conjunctions_buffer = NULL;
// static char* tmp_conjunctions_buffer = NULL;

char conjunctions_buffer[MAX_CONJUNCT_COUNT * sizeof(int)];
char conjunct_buffer[16];

// int atomic_concept_count, atomic_role_count;
// int subclass_ax_count, eqclass_ax_count, subrole_ax_count;

// Pvoid_t atomic_concept_names;
// Pvoid_t atomic_role_names;
// Pvoid_t exists_restrictions_hash;


// return the atomic concept with the given name if it exists
// NULL if it does not exist
Concept* get_atomic_concept(unsigned char* name, TBox* tbox) {
	PWord_t pvalue;

	JSLG(pvalue, tbox->atomic_concepts, name);
	if (pvalue == NULL)
			return NULL;
	return (Concept*) *pvalue;
}

// insert the atomic concept with the given name
void put_atomic_concept(unsigned char* name, Concept* c, TBox* tbox) {
	PWord_t pvalue;

	JSLI(pvalue, tbox->atomic_concepts, name);
	if (pvalue == PJERR) {
		fprintf(stderr, "could not insert atomic concept %s, aborting\n", name);
		exit(EXIT_FAILURE);
	}
	*pvalue = (Word_t) c;
}

// return the atomic role with the given name if it exists
// NULL if it does not exist
Role* get_atomic_role(unsigned char* name, TBox* tbox) {
	PWord_t pvalue;
	JSLG(pvalue, tbox->atomic_roles, name);
	if (pvalue == NULL)
 		return NULL;
	return (Role*) *pvalue;
}

// insert the atomic role with the given name
void put_atomic_role(unsigned char* name, Role* r, TBox* tbox) {
	PWord_t pvalue;

	JSLI(pvalue, tbox->atomic_roles, name);
	if (pvalue == PJERR) {
		fprintf(stderr, "could not insert atomic role %s, aborting", name);
		exit(EXIT_FAILURE);
	}
	*pvalue = (Word_t) r;
}

// get the existential restriction with role r and filler f from hash
Concept* get_exists_restriction(int r, int f, TBox* tbox) {
	PWord_t pvalue;
	unsigned char exists_restriction_buffer[16];

	BUILD_EXISTS_RESTRICTION_ID(r,f);
	JSLG(pvalue, tbox->exists_restrictions, exists_restriction_buffer);
	if (pvalue == NULL)
		return NULL;
	return (Concept*) *pvalue;
}

// put the existential restriction with role r and filler f into hash
void put_exists_restriction(int r, int f, Concept* c, TBox* tbox) {
	PWord_t pvalue;

	BUILD_EXISTS_RESTRICTION_ID(r,f);
	JSLI(pvalue, tbox->exists_restrictions, exists_restriction_buffer);
	if (pvalue == PJERR) {
		fprintf(stderr, "could not insert existential restriction (some %d %d), aborting", r, f);
		exit(EXIT_FAILURE);
	}
	*pvalue = (Word_t) c;
}

// comparison function for qsorting conjucts based on ids
static int compare_conjunct(const void* c1, const void* c2) {
	if (((Concept*) c1)->id < ((Concept*) c2)->id)
		return -1;
	if (((Concept*) c1)->id == ((Concept*) c2)->id)
		return 0;
	return 1;
}

// builds a conjuction id based on ids of the conjucts
// and leaves it in the conjuctions_buffer
void build_conjunction_id(int size, Concept** conjuncts) {
	int i;
	/*
	// the extra 'size' is for the underscores in between
	printf("size: %d\n", size);
	tmp_conjunctions_buffer = (char*) realloc(conjunctions_buffer, size * sizeof(char) + size);
	assert(tmp_conjunctions_buffer != NULL);
	conjunctions_buffer = tmp_conjunctions_buffer;
	*/
	sprintf((char*) conjunctions_buffer, "%c", '\0');
	qsort(conjuncts, size, sizeof(Concept*), compare_conjunct);
	for (i = 0; i < size; i++) {
		snprintf((char*) conjunct_buffer, 16, "%d_", conjuncts[i]->id);
		strcat(conjunctions_buffer, conjunct_buffer);
	}
}

Concept* get_conjunction(int size, Concept** conjuncts, TBox* tbox) {
	PWord_t pvalue;

	build_conjunction_id(size, conjuncts);
	JSLG(pvalue, tbox->conjunctions, (unsigned char*) conjunctions_buffer);
	if (pvalue == NULL)
		return NULL;
	return (Concept*) *pvalue;
}

void put_conjunction(int size, Concept* c, TBox* tbox) {
	PWord_t pvalue;

	build_conjunction_id(size, c->description.conj->conjuncts);
	JSLI(pvalue, tbox->conjunctions, (unsigned char*) conjunctions_buffer);
	if (pvalue == PJERR) {
		fprintf(stderr, "could not insert conjunction, aborting\n");
		exit(EXIT_FAILURE);
	}
	*pvalue = (Word_t) c;
}
